home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 December / PCWorld_2007-12_cd.bin / v cisle / htttrack / httrack-3.41-3.exe / {app} / src / htsftp.c < prev    next >
C/C++ Source or Header  |  2006-08-15  |  33KB  |  1,113 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: basic FTP protocol manager                             */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. // Gestion protocole ftp
  41. // Version .05 (01/2000)
  42.  
  43. #include "htsftp.h"
  44.  
  45. #include "htscore.h"
  46. #include "htsthread.h"
  47. #ifdef _WIN32
  48. #else
  49. //inet_ntoa
  50. #include <arpa/inet.h>
  51. #endif
  52.  
  53. #ifdef _WIN32
  54. #ifndef __cplusplus
  55. // DOS
  56. #ifndef  _WIN32_WCE
  57. #include <process.h>    /* _beginthread, _endthread */
  58. #endif
  59. #endif
  60. #endif
  61.  
  62. // ftp mode passif
  63. // #if HTS_INET6==0
  64. #define FTP_PASV 1
  65. // #else
  66. // no passive mode for v6
  67. // #define FTP_PASV 0
  68. // #endif
  69.  
  70. #define FTP_DEBUG 0
  71. //#define FORK_DEBUG 0
  72.  
  73. #if USE_BEGINTHREAD
  74.  
  75. void back_launch_ftp( void* pP ) {
  76.     FTPDownloadStruct *pStruct = (FTPDownloadStruct*)pP;
  77.   if (pStruct == NULL)
  78.     return ;
  79.  
  80.     if (pStruct == NULL) {
  81. #if FTP_DEBUG
  82.     printf("[ftp error: no args]\n");
  83. #endif
  84.     return ;
  85.   }
  86.  
  87.   /* Initialize */ 
  88.   hts_init();
  89.  
  90.   // lancer ftp
  91. #if FTP_DEBUG
  92.   printf("[Launching main ftp routine]\n");
  93. #endif
  94.   run_launch_ftp(pStruct);
  95.   // prΩt
  96.     pStruct->pBack->status=STATUS_FTP_READY;
  97.  
  98.     /* Delete structure */
  99.     free(pP);
  100.  
  101.   /* Uninitialize */
  102.   hts_uninit();
  103.   return ;
  104. }
  105. // lancer en back
  106. void launch_ftp(FTPDownloadStruct* params) {
  107.   // DOS
  108. #if FTP_DEBUG
  109.   printf("[Launching main ftp thread]\n");
  110. #endif
  111.   hts_newthread(back_launch_ftp, (void*) params);
  112. }
  113.  
  114. #else
  115. #error No more supported
  116. #endif
  117.  
  118. // pour l'arrΩt du ftp
  119. #ifdef _WIN32
  120. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  121. #else
  122. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  123. #endif
  124. #define _HALT_FTP { \
  125.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  126.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  127.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  128. }
  129. #define _CHECK_HALT_FTP \
  130.   if (stop_ftp(back)) { \
  131.   _HALT_FTP \
  132.   return 0; \
  133.   }
  134.  
  135. // la vΘritable fonction une fois lancΘes les routines thread/fork
  136. int run_launch_ftp(FTPDownloadStruct *pStruct) {
  137.     lien_back* back = pStruct->pBack;
  138.     httrackp *opt = pStruct->pOpt;
  139.   char user[256]="anonymous";
  140.   char pass[256]="user@";
  141.   char line_retr[2048];
  142.   int port=21;
  143. #if FTP_PASV
  144.   int port_pasv=0;
  145. #endif
  146.   char BIGSTK adr_ip[1024];
  147.   char *adr,*real_adr;
  148.   char* ftp_filename="";
  149.   int timeout = 300;    // timeout
  150.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  151.   int transfer_list=0;  // directory
  152.   int rest_understood=0;  // rest command understood
  153.   t_fullhostent fullhostent_buffer;   // buffer pour resolver
  154.   //
  155.   T_SOC soc_ctl=INVALID_SOCKET;
  156.   T_SOC soc_servdat=INVALID_SOCKET;
  157.   T_SOC soc_dat=INVALID_SOCKET;
  158.   //
  159.   SOCaddr server_data;
  160.   int server_data_size=sizeof(server_data);
  161.   //
  162.   line_retr[0]=adr_ip[0]='\0';
  163.   
  164.   timeout=300;
  165.   
  166.   // effacer
  167.   strcpybuff(back->r.msg,"");
  168.   back->r.statuscode=0;
  169.   back->r.size=0;
  170.   
  171.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  172.   real_adr = strchr(back->url_adr,':');
  173.   if (real_adr) real_adr++;
  174.   else real_adr=back->url_adr;
  175.   while(*real_adr=='/') real_adr++;    // sauter /
  176.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  177.     int i=-1;
  178.     pass[0]='\0';
  179.     do {
  180.       i++;
  181.       user[i]=real_adr[i];
  182.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  183.     user[i]='\0';
  184.     if (real_adr[i]==':') {    // pass
  185.       int j=-1;
  186.       i++;  // oui on saute aussi le :
  187.       do {
  188.         j++;
  189.         pass[j]=real_adr[i+j];
  190.       } while( ((&real_adr[i+j+1]) < adr) && (real_adr[i+j]) );
  191.       pass[j]='\0';
  192.     }
  193.   }
  194.   
  195.   // Calculer RETR <nom>
  196.   {
  197.     char* a;
  198. #if 0
  199.     a=back->url_fil + strlen(back->url_fil)-1;
  200.     while( (a > back->url_fil) && (*a!='/')) a--;
  201.     if (*a != '/') {
  202.       a = NULL;
  203.     }
  204. #else
  205.     a = back->url_fil;
  206. #endif
  207.     if (a != NULL && *a != '\0') {
  208. #if 0
  209.       a++;    // sauter /
  210. #endif
  211.       ftp_filename=a;
  212.       if (strnotempty(a)) {
  213.                 char catbuff[CATBUFF_SIZE];
  214.         char* ua=unescape_http(catbuff,a);
  215.         int len_a = (int) strlen(ua);
  216.         if (len_a > 0 && ua[len_a -1] == '/') {     /* obviously a directory listing */
  217.           transfer_list=1;
  218.           sprintf(line_retr,"LIST -A %s",ua);
  219.         } else if (
  220.           (strchr(ua, ' '))
  221.           ||
  222.           (strchr(ua, '\"'))
  223.           ||
  224.           (strchr(ua, '\''))
  225.           ) {
  226.           sprintf(line_retr,"RETR \"%s\"",ua);
  227.         } else {      /* Regular one */
  228.           sprintf(line_retr,"RETR %s",ua);
  229.         }
  230.       } else {
  231.         transfer_list=1;
  232.         sprintf(line_retr,"LIST -A");
  233.       }
  234.     } else {
  235.       strcpybuff(back->r.msg,"Unexpected PORT error");
  236.       // back->status=STATUS_FTP_READY;    // fini
  237.       back->r.statuscode=STATUSCODE_INVALID;
  238.     }
  239.   }
  240.   
  241. #if FTP_DEBUG
  242.   printf("Connecting to %s...\n",adr);
  243. #endif
  244.   
  245.   // connexion
  246.   {
  247.     SOCaddr server;
  248.     int server_size=sizeof(server);
  249.     t_hostent* hp;    
  250.     char * a;
  251.     char _adr[256];
  252.     _adr[0]='\0';
  253.     //T_SOC soc_ctl;
  254.     // effacer structure
  255.     memset(&server, 0, sizeof(server));
  256.     
  257.     // port
  258.     a=strchr(adr,':');    // port
  259.     if (a) {
  260.       sscanf(a+1,"%d",&port);
  261.       strncatbuff(_adr,adr,(int) (a - adr));
  262.     } else
  263.       strcpybuff(_adr,adr);
  264.     
  265.     // rΘcupΘrer adresse rΘsolue
  266.     strcpybuff(back->info,"host name");
  267.     hp = hts_gethostbyname(opt,_adr, &fullhostent_buffer);
  268.     if (hp == NULL) {
  269.       strcpybuff(back->r.msg,"Unable to get server's address");
  270.       // back->status=STATUS_FTP_READY;    // fini
  271.       back->r.statuscode=STATUSCODE_NON_FATAL;
  272.       _HALT_FTP
  273.         return 0;
  274.     }
  275.     _CHECK_HALT_FTP;
  276.     
  277.     // copie adresse
  278.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  279.     // copie adresse pour cnx data
  280.     SOCaddr_copyaddr(server_data, server_data_size, hp->h_addr_list[0], hp->h_length);
  281.     // memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
  282.     
  283.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  284.     soc_ctl = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  285.     if (soc_ctl==INVALID_SOCKET) {
  286.       strcpybuff(back->r.msg,"Unable to create a socket");
  287.       // back->status=STATUS_FTP_READY;    // fini
  288.       back->r.statuscode=STATUSCODE_INVALID;
  289.       _HALT_FTP
  290.         return 0;
  291.     }
  292.  
  293.     SOCaddr_initport(server, port);
  294.     // server.sin_port = htons((unsigned short int) port);
  295.     
  296.     // connexion (bloquante, on est en thread)
  297.     strcpybuff(back->info,"connect");
  298.  
  299. #ifdef _WIN32
  300.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, server_size) != 0) {
  301. #else
  302.       if (connect(soc_ctl, (struct sockaddr *)&server, server_size) == -1) {
  303. #endif
  304.         strcpybuff(back->r.msg,"Unable to connect to the server");
  305.         // back->status=STATUS_FTP_READY;    // fini
  306.         back->r.statuscode=STATUSCODE_INVALID;
  307.         _HALT_FTP
  308.           return 0;
  309. #ifdef _WIN32
  310.       }
  311. #else
  312.     }
  313. #endif
  314.     _CHECK_HALT_FTP;
  315.     
  316.     {
  317.       char BIGSTK line[1024];
  318.       // envoi du login
  319.       
  320.       // --USER--
  321.       get_ftp_line(soc_ctl,line,timeout);    // en tΩte
  322.       _CHECK_HALT_FTP;
  323.       
  324.       if (line[0]=='2') {        // ok, connectΘ
  325.         strcpybuff(back->info,"login: user");
  326.         sprintf(line,"USER %s",user);
  327.         send_line(soc_ctl,line);
  328.         get_ftp_line(soc_ctl,line,timeout);
  329.         _CHECK_HALT_FTP;      
  330.         if ((line[0]=='3') || (line[0]=='2')) {
  331.           // --PASS--
  332.           strcpybuff(back->info,"login: pass");
  333.           sprintf(line,"PASS %s",pass);
  334.           send_line(soc_ctl,line);
  335.           get_ftp_line(soc_ctl,line,timeout);
  336.           _CHECK_HALT_FTP;      
  337.           if (line[0]=='2') {  // ok
  338.             send_line(soc_ctl,"TYPE I");
  339.             get_ftp_line(soc_ctl,line,timeout);
  340.             _CHECK_HALT_FTP;      
  341.             if (line[0]=='2') {
  342.               // ok
  343.             } else {
  344.               strcpybuff(back->r.msg,"TYPE I error");
  345.               // back->status=STATUS_FTP_READY;    // fini
  346.               back->r.statuscode=STATUSCODE_INVALID;
  347.             }
  348. #if 0
  349.             // --CWD--
  350.             char* a;
  351.             a=back->url_fil + strlen(back->url_fil)-1;
  352.             while( (a > back->url_fil) && (*a!='/')) a--;
  353.             if (*a == '/') {    // ok repΘrΘ
  354.               char BIGSTK target[1024];
  355.               target[0]='\0';
  356.               strncatbuff(target,back->url_fil,(int) (a - back->url_fil));
  357.               if (strnotempty(target)==0)
  358.                 strcatbuff(target,"/");
  359.               strcpybuff(back->info,"cwd");
  360.               sprintf(line,"CWD %s",target);
  361.               send_line(soc_ctl,line);
  362.               get_ftp_line(soc_ctl,line,timeout);
  363.               _CHECK_HALT_FTP;      
  364.               if (line[0]=='2') {
  365.                 send_line(soc_ctl,"TYPE I");
  366.                 get_ftp_line(soc_ctl,line,timeout);
  367.                 _CHECK_HALT_FTP;      
  368.                 if (line[0]=='2') {
  369.                   // ok..
  370.                 } else {
  371.                   strcpybuff(back->r.msg,"TYPE I error");
  372.                   // back->status=STATUS_FTP_READY;    // fini
  373.                   back->r.statuscode=STATUSCODE_INVALID;
  374.                 }
  375.               } else {
  376.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  377.                 // back->status=STATUS_FTP_READY;    // fini
  378.                 back->r.statuscode=STATUSCODE_INVALID;
  379.               }    // sinon on est prΩts
  380.             } else {
  381.               strcpybuff(back->r.msg,"Unexpected ftp error");
  382.               // back->status=STATUS_FTP_READY;    // fini
  383.               back->r.statuscode=STATUSCODE_INVALID;
  384.             }
  385. #endif
  386.             
  387.           } else {
  388.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  389.             // back->status=STATUS_FTP_READY;    // fini
  390.             back->r.statuscode=STATUSCODE_INVALID;
  391.           }
  392.         } else {
  393.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  394.           // back->status=STATUS_FTP_READY;    // fini
  395.           back->r.statuscode=STATUSCODE_INVALID;
  396.         }
  397.       } else {
  398.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  399.         // back->status=STATUS_FTP_READY;    // fini
  400.         back->r.statuscode=STATUSCODE_INVALID;
  401.       }
  402.      
  403.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  404.       if (back->r.statuscode != -1) {
  405.  
  406.         
  407.         //
  408.         // PrΘ-REST
  409.         //
  410. #if FTP_PASV
  411.         if (SOCaddr_getproto(server, server_size) == '1') {
  412.           strcpybuff(back->info,"pasv");
  413.           sprintf(line,"PASV");
  414.           send_line(soc_ctl,line);
  415.           get_ftp_line(soc_ctl,line,timeout);
  416.         } else { /* ipv6 */
  417.           line[0]='\0';
  418.         }
  419.         _CHECK_HALT_FTP;      
  420.         if (line[0]=='2') {
  421.           char *a,*b,*c;
  422.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  423.           if (a) {
  424.            
  425.             // -- analyse de l'adresse IP et du port --
  426.             a++;
  427.             b=strchr(a,',');
  428.             if (b) b=strchr(b+1,',');
  429.             if (b) b=strchr(b+1,',');
  430.             if (b) b=strchr(b+1,',');
  431.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  432.             if (b) *b='\0';
  433.             //
  434.             strcpybuff(adr_ip,a);       // copier adresse ip
  435.             //
  436.             if (b) {
  437.               a=b+1;  // dΘbut du port
  438.               b=strchr(a,'.');
  439.               if (b) {
  440.                 int n1,n2;
  441.                 //
  442.                 *b='\0';
  443.                 b++;
  444.                 c=strchr(b,')');
  445.                 if (c) {
  446.                   *c='\0';
  447.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  448.                     port_pasv=n2+(n1<<8);
  449.                   }
  450.                 } else {
  451.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  452.                 }    // sinon on est prΩts
  453.               }
  454.             }
  455.             // -- fin analyse de l'adresse IP et du port --
  456.           } else {
  457.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  458.             // back->status=STATUS_FTP_READY;    // fini
  459.             back->r.statuscode=STATUSCODE_INVALID;
  460.           }    // sinon on est prΩts
  461.         } else {
  462.           /*
  463.             * try epsv (ipv6) *
  464.           */
  465.           strcpybuff(back->info,"pasv");
  466.           sprintf(line,"EPSV");
  467.           send_line(soc_ctl,line);
  468.           get_ftp_line(soc_ctl,line,timeout);
  469.           _CHECK_HALT_FTP;      
  470.           if (line[0]=='2') { /* got it */
  471.             char *a;
  472.             a=strchr(line,'(');       // exemple: 229 Entering Extended Passive Mode (|||6446|)
  473.             if (
  474.               (a != NULL)
  475.               &&
  476.               (*a == '(') 
  477.               && (*(a+1))
  478.               && (*(a+1) == *(a+2)) && (*(a+1) == *(a+3))
  479.               && (isdigit(*(a+4)))
  480.               && (*(a+5))
  481.               ) {
  482.               unsigned int n1 = 0;
  483.               if (sscanf(a+4,"%d",&n1)==1) {
  484.                 if ((n1 < 65535) && (n1 > 0)) {
  485.                   port_pasv=n1;
  486.                 }
  487.               }
  488.             } else {
  489.               sprintf(back->r.msg,"EPSV incorrect: %s",linejmp(line));
  490.               // back->status=STATUS_FTP_READY;    // fini
  491.               back->r.statuscode=STATUSCODE_INVALID;
  492.             }
  493.           } else {
  494.             sprintf(back->r.msg,"PASV/EPSV error: %s",linejmp(line));
  495.             // back->status=STATUS_FTP_READY;    // fini
  496.             back->r.statuscode=STATUSCODE_INVALID;
  497.           }    // sinon on est prΩts
  498.         }
  499. #else
  500.         // rien α faire avant
  501. #endif
  502.           
  503. #if FTP_PASV
  504.         if (port_pasv) {
  505. #endif
  506.           // SIZE
  507.           if (back->r.statuscode != -1) {
  508.             if (!transfer_list) {
  509.                             char catbuff[CATBUFF_SIZE];
  510.               char* ua=unescape_http(catbuff,ftp_filename);
  511.               if (
  512.                 (strchr(ua, ' '))
  513.                 ||
  514.                 (strchr(ua, '\"'))
  515.                 ||
  516.                 (strchr(ua, '\''))
  517.                 ) {
  518.                 sprintf(line,"SIZE \"%s\"", ua);
  519.               } else {
  520.                 sprintf(line,"SIZE %s", ua);
  521.               }
  522.               
  523.               // SIZE?
  524.               strcpybuff(back->info,"size");
  525.               send_line(soc_ctl,line);
  526.               get_ftp_line(soc_ctl,line,timeout);
  527.               _CHECK_HALT_FTP;      
  528.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  529.                 char* szstr = strchr(line, ' ');
  530.                 if (szstr) {
  531.                   LLint size = 0;
  532.                   szstr++;
  533.                   if (sscanf(szstr, LLintP, &size) == 1) {
  534.                     back->r.totalsize = size;
  535.                   }
  536.                 }
  537.  
  538.                 // REST?
  539.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  540.                   strcpybuff(back->info,"rest");
  541.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  542.                   send_line(soc_ctl,line);
  543.                   get_ftp_line(soc_ctl,line,timeout);
  544.                   _CHECK_HALT_FTP;      
  545.                   if ((line[0]=='3') || (line[0]=='2')) {  // ok
  546.                     rest_understood=1;
  547.                   } // sinon tant pis 
  548.                 } 
  549.               }  // sinon tant pis 
  550.             }
  551.           }
  552. #if FTP_PASV
  553.         }
  554. #endif
  555.  
  556.         //
  557.         // Post-REST
  558.         //
  559. #if FTP_PASV
  560.         // Ok, se connecter
  561.         if (port_pasv) {
  562.           SOCaddr server;
  563.           int server_size=sizeof(server);
  564.           t_hostent* hp;    
  565.           // effacer structure
  566.           memset(&server, 0, sizeof(server));
  567.           
  568.           // infos
  569.           strcpybuff(back->info,"resolv");
  570.           
  571.           // rΘsoudre
  572.           if (adr_ip[0]) {
  573.             hp = hts_gethostbyname(opt,adr_ip, &fullhostent_buffer);
  574.             if (hp) {
  575.               SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  576.             } else {
  577.               server_size=0;
  578.             }
  579.           } else {
  580.             memcpy(&server, &server_data, sizeof(server_data));
  581.             server_size=server_data_size;
  582.           }
  583.           
  584.           // infos
  585.           strcpybuff(back->info,"cnxdata");
  586. #if FTP_DEBUG
  587.           printf("Data: Connecting to %s:%d...\n", adr_ip, port_pasv);
  588. #endif
  589.           if (server_size > 0) {
  590.             // socket
  591.             soc_dat = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  592.             if (soc_dat != INVALID_SOCKET) {
  593.               // structure: connexion au domaine internet, port 80 (ou autre)
  594.               SOCaddr_initport(server, port_pasv);
  595.               // server.sin_port = htons((unsigned short int) port_pasv);
  596. #ifdef _WIN32
  597.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, server_size) == 0) {
  598. #else
  599.               if (connect(soc_dat, (struct sockaddr *)&server, server_size) != -1) {
  600. #endif
  601.                 strcpybuff(back->info,"retr");
  602.                 strcpybuff(line,line_retr);
  603.                 send_line(soc_ctl,line);
  604.                 get_ftp_line(soc_ctl,line,timeout);
  605.                 _CHECK_HALT_FTP;      
  606.                 if (line[0]=='1') {
  607.                   // OK
  608.                 } else {
  609.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  610.                   //
  611.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  612.                   // back->status=STATUS_FTP_READY;    // fini
  613.                   back->r.statuscode=STATUSCODE_INVALID;
  614.                 }    // sinon on est prΩts
  615.               } else {
  616. #if FTP_DEBUG
  617.                 printf("Data: unable to connect\n");
  618. #endif
  619.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  620.                 //
  621.                 strcpybuff(back->r.msg,"Unable to connect");
  622.                 // back->status=STATUS_FTP_READY;    // fini
  623.                 back->r.statuscode=STATUSCODE_INVALID;
  624.               }    // sinon on est prΩts
  625.             } else {
  626.               strcpybuff(back->r.msg,"Unable to create a socket");
  627.               // back->status=STATUS_FTP_READY;    // fini
  628.               back->r.statuscode=STATUSCODE_INVALID;
  629.             }    // sinon on est prΩts
  630.           } else {
  631.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  632.             // back->status=STATUS_FTP_READY;    // fini
  633.             back->r.statuscode=STATUSCODE_INVALID;
  634.           }    // sinon on est prΩts
  635.         } else {
  636.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  637.           // back->status=STATUS_FTP_READY;    // fini
  638.           back->r.statuscode=STATUSCODE_INVALID;
  639.         }    // sinon on est prΩts
  640. #else
  641.         //T_SOC soc_servdat;
  642.         strcpybuff(back->info,"listening");
  643.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  644.           _CHECK_HALT_FTP;      
  645.           send_line(soc_ctl,line);          // envoi du RETR
  646.           get_ftp_line(soc_ctl,line,timeout);
  647.           _CHECK_HALT_FTP;      
  648.           if (line[0]=='2') {  // ok
  649.             strcpybuff(back->info,"retr");
  650.             strcpybuff(line,line_retr);
  651.             send_line(soc_ctl,line);
  652.             get_ftp_line(soc_ctl,line,timeout);
  653.             _CHECK_HALT_FTP;      
  654.             if (line[0]=='1') {
  655.               //T_SOC soc_dat;
  656.               struct sockaddr dummyaddr;
  657.               int dummylen = sizeof(struct sockaddr);
  658.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  659.                 strcpybuff(back->r.msg,"Unable to accept connection");
  660.                 // back->status=STATUS_FTP_READY;    // fini
  661.                 back->r.statuscode=STATUSCODE_INVALID;
  662.               }
  663.             } else {
  664.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  665.               // back->status=STATUS_FTP_READY;    // fini
  666.               back->r.statuscode=STATUSCODE_INVALID;
  667.             }
  668.           } else {
  669.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  670.             // back->status=STATUS_FTP_READY;    // fini
  671.             back->r.statuscode=STATUSCODE_INVALID;
  672.           }
  673. #ifdef _WIN32
  674.           closesocket(soc_servdat);
  675. #else
  676.           close(soc_servdat);
  677. #endif
  678.         } else {
  679.           strcpybuff(back->r.msg,"Unable to listen to a port");
  680.           // back->status=STATUS_FTP_READY;    // fini
  681.           back->r.statuscode=STATUSCODE_INVALID;
  682.         }
  683. #endif
  684.         
  685.         //
  686.         // Ok, connexion initiΘe
  687.         //
  688.         if (soc_dat != INVALID_SOCKET) {
  689.           if (rest_understood) {         // REST envoyΘe et comprise
  690.             file_notify(opt, back->url_adr, back->url_fil, back->url_sav, 0, 1, 0);
  691.                         back->r.fp = fileappend(&opt->state.strc, back->url_sav);
  692.           } else {
  693.             file_notify(opt, back->url_adr, back->url_fil, back->url_sav, 1, 1, 0);
  694.             back->r.fp = filecreate(&opt->state.strc, back->url_sav);
  695.           }
  696.           strcpybuff(back->info,"receiving");
  697.           if (back->r.fp != NULL) {
  698.             char BIGSTK buff[1024];
  699.             int len=1;
  700.             int read_len=1024;
  701.             //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  702.             
  703.             while( (len>0) && (!stop_ftp(back)) ) {
  704.               // attendre les donnΘes
  705.               len=1;    // pas d'erreur pour le moment
  706.               switch(wait_socket_receive(soc_dat,timeout)) {
  707.               case -1:
  708.                 strcpybuff(back->r.msg,"FTP read error");
  709.                 // back->status=STATUS_FTP_READY;    // fini
  710.                 back->r.statuscode=STATUSCODE_INVALID;
  711.                 len=0;    // fin
  712.                 break;
  713.               case 0:
  714.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  715.                 // back->status=STATUS_FTP_READY;    // fini
  716.                 back->r.statuscode=STATUSCODE_INVALID;
  717.                 len=0;    // fin
  718.                 break;
  719.               }
  720.               
  721.               // rΘception
  722.               if (len) {
  723.                 len=recv(soc_dat,buff,read_len,0);
  724.                 if (len>0) {
  725.                   back->r.size+=len;
  726.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  727.                   if (back->r.fp) {
  728.                     if ((INTsys)fwrite(buff,1,(INTsys)len,back->r.fp) != len) {
  729.                       /*
  730.                       int fcheck;
  731.                       if ((fcheck=check_fatal_io_errno())) {
  732.                         opt->state.exit_xh=-1;
  733.                       }
  734.                       */
  735.                       strcpybuff(back->r.msg,"Write error");
  736.                       // back->status=STATUS_FTP_READY;    // fini
  737.                       back->r.statuscode=STATUSCODE_INVALID;
  738.                       len=0;  // error
  739.                     }
  740.                   } else {
  741.                     strcpybuff(back->r.msg,"Unexpected write error");
  742.                     // back->status=STATUS_FTP_READY;    // fini
  743.                     back->r.statuscode=STATUSCODE_INVALID;
  744.                   }
  745.                 } else {        // Erreur ou terminΘ
  746.                   // back->status=STATUS_FTP_READY;    // fini
  747.                   back->r.statuscode=0;
  748.                   if (back->r.totalsize > 0 && back->r.size != back->r.totalsize) {
  749.                     back->r.statuscode=STATUSCODE_INVALID;
  750.                     strcpybuff(back->r.msg,"FTP file incomplete");
  751.                   }
  752.                 }
  753.                 read_len=1024; 
  754.                 //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  755.               }
  756.             }
  757.             if (back->r.fp) { 
  758.               fclose(back->r.fp); 
  759.               back->r.fp=NULL;
  760.             }
  761.           } else {
  762.             strcpybuff(back->r.msg,"Unable to write file");
  763.             // back->status=STATUS_FTP_READY;    // fini
  764.             back->r.statuscode=STATUSCODE_INVALID;
  765.           }
  766. #ifdef _WIN32
  767.           closesocket(soc_dat);
  768. #else
  769.           close(soc_dat);
  770. #endif
  771.           
  772.           // 226 Transfer complete?
  773.           if (back->r.statuscode != -1) {
  774.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  775.               // rΘcupΘrer 226 transfer complete
  776.               get_ftp_line(soc_ctl,line,timeout);
  777.               if (line[0]=='2') {       // OK
  778.                 strcpybuff(back->r.msg,"OK");
  779.                 // back->status=STATUS_FTP_READY;    // fini
  780.                 back->r.statuscode=HTTP_OK;
  781.               } else {
  782.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  783.                 // back->status=STATUS_FTP_READY;    // fini
  784.                 back->r.statuscode=STATUSCODE_INVALID;
  785.               }
  786.             } else {
  787.               strcpybuff(back->r.msg,"FTP read error");
  788.               // back->status=STATUS_FTP_READY;    // fini
  789.               back->r.statuscode=STATUSCODE_INVALID;
  790.             }
  791.           }
  792.           
  793.         }
  794.         
  795.         
  796.         
  797.       }
  798.       
  799.       
  800.     }
  801.     
  802.     _CHECK_HALT_FTP;
  803.     strcpybuff(back->info,"quit");
  804.     send_line(soc_ctl,"QUIT");    // bye bye
  805.     get_ftp_line(soc_ctl,NULL,timeout);
  806. #ifdef _WIN32
  807.     closesocket(soc_ctl);
  808. #else
  809.     close(soc_ctl);
  810. #endif
  811.   }
  812.   
  813.   if (back->r.statuscode!=-1) {
  814.     back->r.statuscode=HTTP_OK;
  815.     strcpybuff(back->r.msg,"OK");
  816.   }
  817.   // back->status=STATUS_FTP_READY;    // fini
  818.   return 0;
  819. }
  820.  
  821.  
  822.  
  823. // ouverture d'un port
  824. T_SOC get_datasocket(char* to_send) {
  825.   T_SOC soc = INVALID_SOCKET;
  826.   char h_loc[256+2];
  827.   
  828.   to_send[0]='\0';
  829.   if (gethostname(h_loc,256)==0) {    // host name
  830.     SOCaddr server;
  831.     int server_size=sizeof(server);
  832.     t_hostent* hp_loc;
  833.     t_fullhostent buffer;
  834.  
  835.     // effacer structure
  836.     memset(&server, 0, sizeof(server));
  837.  
  838.     if ( (hp_loc=vxgethostbyname(h_loc, &buffer)) ) {  // notre host
  839.  
  840.       // copie adresse
  841.       SOCaddr_copyaddr(server, server_size, hp_loc->h_addr_list[0], hp_loc->h_length);
  842.  
  843.       if ( (soc = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0)) != INVALID_SOCKET) {
  844.  
  845.         if ( bind(soc,(struct sockaddr*) &server, server_size) == 0 ) {
  846.           SOCaddr server2;
  847.           int len;
  848.           len=sizeof(server2);
  849.           // effacer structure
  850.           memset(&server2, 0, sizeof(server2));
  851.           if (getsockname(soc,(struct sockaddr*) &server2, &len) == 0) {
  852.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  853.             if (listen(soc,10)>=0) {    // au pif le 10
  854. #if HTS_INET6==0
  855.               unsigned short int a,n1,n2;
  856.               // calculer port
  857.               a  = SOCaddr_sinport(server2);
  858.               n1 = (a & 0xff);
  859.               n2 = ((a>>8) & 0xff);
  860.               {
  861.                 char dots[256+2];
  862.                 char dot[256+2];
  863.                 char* a;
  864.                 SOCaddr_inetntoa(dot, 256, server2, sizeof(server2));
  865.                 //
  866.                 dots[0]='\0';
  867.                 strncatbuff(dots, dot, 128);
  868.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  869.                 while( (a=strchr(dots,':')) ) *a=',';    // virgules!
  870.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  871.               }
  872. #else
  873.               /*
  874.                 EPRT |1|132.235.1.2|6275|
  875.                 EPRT |2|1080::8:800:200C:417A|5282|
  876.               */
  877.               {
  878.                 char dot[256+2];
  879.                 SOCaddr_inetntoa(dot, 256, server2, len);
  880.                 sprintf(to_send,"EPRT |%c|%s|%d|", SOCaddr_getproto(server2, len), dot, SOCaddr_sinport(server2));  
  881.               }
  882. #endif
  883.               
  884.             } else {
  885. #ifdef _WIN32
  886.               closesocket(soc);
  887. #else
  888.               close(soc);
  889. #endif
  890.               soc=INVALID_SOCKET;
  891.             }
  892.             
  893.             
  894.           } else {
  895. #ifdef _WIN32
  896.             closesocket(soc);
  897. #else
  898.             close(soc);
  899. #endif
  900.             soc=INVALID_SOCKET;
  901.           }
  902.           
  903.           
  904.         } else {
  905. #ifdef _WIN32
  906.           closesocket(soc);
  907. #else
  908.           close(soc);
  909. #endif
  910.           soc=INVALID_SOCKET;
  911.         }
  912.       }
  913.     }
  914.   }
  915.   
  916.   
  917.   return soc;
  918. }
  919.  
  920. #if FTP_DEBUG
  921. FILE* dd=NULL;
  922. #endif
  923.  
  924. // routines de rΘception/Θmission
  925. // 0 = ERROR
  926. int send_line(T_SOC soc,char* data) {
  927.   char BIGSTK line[1024];
  928.   if (_DEBUG_HEAD) {
  929.     if (ioinfo) {
  930.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  931.       fflush(ioinfo);
  932.     }
  933.   }
  934. #if FTP_DEBUG
  935.   if (dd == NULL) dd = fopen("toto.txt","w");
  936.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  937.   printf("---> %s",data); fflush(stdout);
  938. #endif
  939.   sprintf(line,"%s\x0d\x0a",data);
  940.   if (check_socket_connect(soc) != 1) {
  941. #if FTP_DEBUG
  942.     printf("!SOC WRITE ERROR\n");
  943. #endif
  944.     return 0;    // erreur, plus connectΘ!
  945.   }
  946. #if FTP_DEBUG
  947.   {
  948.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  949.     printf("%s\x0d\x0a",data); fflush(stdout);
  950.     return r;
  951.   }
  952. #else
  953.   return (send(soc,line,(int)strlen(line),0) == (int) strlen(line));
  954. #endif
  955. }
  956.  
  957. int get_ftp_line(T_SOC soc,char* line,int timeout) {
  958.   char BIGSTK data[1024];
  959.   int i,ok,multiline;
  960. #if FTP_DEBUG
  961.   if (dd == NULL) dd = fopen("toto.txt","w");
  962. #endif
  963.   
  964.   data[0]='\0';
  965.   i=ok=multiline=0; data[3]='\0';
  966.   do {
  967.     char b;                        
  968.     
  969.     // vΘrifier donnΘes
  970.     switch(wait_socket_receive(soc,timeout)) {
  971.     case -1:   // erreur de lecture
  972.       if (line) strcpybuff(line,"500 *read error");
  973.       return 0;
  974.       break;
  975.     case 0:
  976.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  977.       return 0;
  978.       break;
  979.     }
  980.     
  981.     //HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  982.     switch(recv(soc,&b,1,0)) {
  983.       //case 0: break;    // pas encore --> erreur (on attend)!
  984.     case 1:
  985.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  986.       if ((b!=10) && (b!=13))
  987.         data[i++]=b;
  988.       break;
  989.     default:
  990.       if (line) strcpybuff(line,"500 *read error");
  991.       return 0; // error
  992.       break;
  993.     }
  994.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  995.       if (
  996.         (data[3] == '-')
  997.         ||
  998.         ((multiline) && (!isdigit((unsigned char)data[0]))) 
  999.         )
  1000.       {
  1001.         data[3]='\0';
  1002.         i=0;
  1003.         multiline=1;
  1004.       }
  1005.       else
  1006.         ok=1;    // sortir
  1007.     }
  1008.   } while(!ok);
  1009.   data[i++]='\0';
  1010.   
  1011.   if (_DEBUG_HEAD) {
  1012.     if (ioinfo) {
  1013.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  1014.       fflush(ioinfo);
  1015.     }
  1016.   }
  1017. #if FTP_DEBUG
  1018.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  1019.   printf("<--- %s\n",data);
  1020. #endif
  1021.   if (line) strcpybuff(line,data);
  1022.   return (strnotempty(data));
  1023. }
  1024.  
  1025. // sauter NNN
  1026. char* linejmp(char* line) {
  1027.   if (strlen(line)>4)
  1028.     return line+4;
  1029.   else
  1030.     return line;
  1031. }
  1032.  
  1033. // test socket:
  1034. // 0 : no data
  1035. // 1 : data detected
  1036. // -1: error
  1037. int check_socket(T_SOC soc) {
  1038.   fd_set fds,fds_e;           // poll structures
  1039.   struct timeval tv;          // structure for select
  1040.   FD_ZERO(&fds);
  1041.   FD_ZERO(&fds_e); 
  1042.   // socket read 
  1043.   FD_SET(soc,&fds);           
  1044.   // socket error
  1045.   FD_SET(soc,&fds_e);
  1046.   tv.tv_sec=0;
  1047.   tv.tv_usec=0;
  1048.   // poll!     
  1049.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  1050.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1051.     return -1;
  1052.   } else if (FD_ISSET(soc,&fds)) {
  1053.     return 1;
  1054.   }
  1055.   return 0;
  1056. }
  1057. // check if connected
  1058. int check_socket_connect(T_SOC soc) {
  1059.   fd_set fds,fds_e;           // poll structures
  1060.   struct timeval tv;          // structure for select
  1061.   FD_ZERO(&fds);
  1062.   FD_ZERO(&fds_e); 
  1063.   // socket write 
  1064.   FD_SET(soc,&fds);           
  1065.   // socket error
  1066.   FD_SET(soc,&fds_e);
  1067.   tv.tv_sec=0;
  1068.   tv.tv_usec=0;
  1069.   // poll!     
  1070.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  1071.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1072.     return -1;
  1073.   } else if (FD_ISSET(soc,&fds)) {
  1074.     return 1;
  1075.   }
  1076.   return 0;
  1077. }
  1078. // attendre des donnΘes
  1079. int wait_socket_receive(T_SOC soc,int timeout) {
  1080.   // attendre les donnΘes
  1081.   TStamp ltime=time_local();
  1082.   int r;
  1083. #if FTP_DEBUG
  1084.   printf("\x0dWaiting for data "); fflush(stdout);
  1085. #endif
  1086.   while( (!(r = check_socket(soc))) && ( ((int) ((TStamp) (time_local()-ltime))) < timeout )) {
  1087.     Sleep(100);
  1088. #if FTP_DEBUG
  1089.     printf("."); fflush(stdout);
  1090. #endif
  1091.   }
  1092. #if FTP_DEBUG
  1093.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1094. #endif
  1095.   return r;
  1096. }
  1097.  
  1098.  
  1099. // cancel reτu?
  1100. int stop_ftp(lien_back* back) {
  1101.   if (back->stop_ftp) {
  1102.     strcpybuff(back->r.msg, "Cancelled by User");
  1103.     // back->status=STATUS_FTP_READY;    // fini
  1104.     back->r.statuscode=STATUSCODE_INVALID;
  1105.     return 1;
  1106.   }
  1107.   return 0;
  1108. }
  1109.  
  1110.  
  1111.  
  1112.  
  1113.